﻿using System;
using System.Xml;
using Notoric.Model.Elements;

namespace Notoric.Model.Packaging
{
    /// <summary>
    /// Implements the <see cref="XmlPackagePart"/> that holds the linear view of a <see cref="CompositionPart"/>.
    /// </summary>
    public sealed class LinearCompositionViewPart : XmlPackagePart
    {
        #region Constructors

        /// <summary>
        /// Creates a new <see cref="LinearCompositionViewPart"/> instance.
        /// </summary>
        /// <param name="package">
        /// <para>
        /// Type: <see cref="Package"/>
        /// </para>
        /// <para>
        /// The parent package (the package that owns this part).
        /// </para>
        /// </param>
        /// <param name="owner">
        /// <para>
        /// Type: <see cref="CompositionPart"/>
        /// </para>
        /// <para>
        /// The composition package part that is the logical owner of this part.
        /// This must not be <see langword="null"/>.
        /// </para>
        /// </param>
        /// <param name="implementationPart">
        /// <para>
        /// Type: <see cref="System.IO.Packaging.PackagePart"/>
        /// </para>
        /// <para>
        /// An existing part of the parent's <see cref="Notoric.Model.Packaging.Package.ImplementationPackage"/> that implements
        /// the core functionality of this part.
        /// </para>
        /// </param>
        /// <param name="interiorCreator">
        /// <para>
        /// Type: <see cref="SectionInteriorCreator"/>
        /// </para>
        /// <para>
        /// The factory method that will create the interior of the music section.
        /// </para>
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// Any of the arguments is <see langword="null"/>.
        /// </exception>
        internal LinearCompositionViewPart(Package package, CompositionPart owner, System.IO.Packaging.PackagePart implementationPart, SectionInteriorCreator interiorCreator)
            : base(package, owner, implementationPart, true)
        {
            if (owner == null)
                throw new ArgumentNullException("owner");
            if (interiorCreator == null)
                throw new ArgumentNullException("interiorCreator");

            this.interiorCreator = interiorCreator;
        }

        /// <summary>
        /// Creates a new <see cref="LinearCompositionViewPart"/> instance.
        /// </summary>
        /// <param name="package">
        /// <para>
        /// Type: <see cref="Package"/>
        /// </para>
        /// <para>
        /// The parent package (the package that owns this part).
        /// </para>
        /// </param>
        /// <param name="owner">
        /// <para>
        /// Type: <see cref="CompositionPart"/>
        /// </para>
        /// <para>
        /// The composition package part that is the logical owner of this part.
        /// This must not be <see langword="null"/>.
        /// </para>
        /// </param>
        /// <param name="implementationPart">
        /// <para>
        /// Type: <see cref="System.IO.Packaging.PackagePart"/>
        /// </para>
        /// <para>
        /// An existing part of the parent's <see cref="Notoric.Model.Packaging.Package.ImplementationPackage"/> that implements
        /// the core functionality of this part.
        /// </para>
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="package"/>, <paramref name="owner"/> or <paramref name="implementationPart"/> is <see langword="null"/>.
        /// </exception>
        internal LinearCompositionViewPart(Package package, CompositionPart owner, System.IO.Packaging.PackagePart implementationPart)
            : base(package, owner, implementationPart, false)
        {
            if (owner == null)
                throw new ArgumentNullException("owner");
        }

        #endregion

        #region XmlPackagePart Members

        /// <inheritdoc/>
        protected override ModelElement CreateAndLoadRoot(XmlElement element)
        {
            return new MusicSectionElement(this, null, element);
        }

        /// <inheritdoc/>
        protected override ModelElement CreateNewRoot()
        {
            var ownerPart = (CompositionPart)Owner;
            var firstMeasure = (ownerPart.Composition.MeasuresCount > 0 ? ownerPart.Composition.Measures[0] : null);
            var lastMeasure = (ownerPart.Composition.MeasuresCount > 0 ? ownerPart.Composition.Measures[ownerPart.Composition.MeasuresCount - 1] : null);
            
            return new MusicSectionElement(this, null, interiorCreator, Owner as CompositionPart, firstMeasure, lastMeasure);
        }

        #endregion

        #region Public Properties

        /// <summary>
        /// Gets the root music section element.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="MusicSectionElement"/>
        /// </para>
        /// <para>
        /// The root music section element.
        /// Reading this property is the same as writing (<see cref="MusicSectionElement"/>)<see cref="XmlPackagePart.RootElement"/>.
        /// </para>
        /// </value>
        public MusicSectionElement MusicSection
        {
            get { return (MusicSectionElement)RootElement; }
        }

        #endregion

        #region Private Fields

        /// <summary>
        /// Holds the method that creates the interior of the music section.
        /// </summary>
        private SectionInteriorCreator interiorCreator;

        #endregion
    }
}
